library(tidyverse, verbose = F)
source("Funciones.R")

Lectura de Datos

Lo datos corresponde a una matriz 5x5x10. La metadata será X = 1…25 y Z = 1…10 (profundidad), ambos detectores tienen la misma metadata.

##Metadata
Metadata <- data.frame(x = rep(1:100, each = 11), 
                       z = rep(1:11, 100))

Comp.data <- data.frame(muestra = c("ss406", "ss407", "ss408", "ss409", "ss410"), 
                        C = c(0.19,0.50,0.28,0.11,0.39),
                        Mn = c(0.53,0.13,0.64,0.48,0.43),
                        Ni = c(1.69,0.61,4.58,3.14,2.04),
                        Cr = c(2.12,3.00,0.09,1.22,1.72),
                        Mo = c(1.03,0.82,0.14,0.77,0.41),
                        Cu = c(0.32,0.43,0.73,0.23,0.47))

DEMON

data.dir <- "Data/demon/"

wl <- read_tsv(paste(data.dir,"ss406.asc",sep = ""), col_names = F, progress = F, show_col_types = F) %>% 
        .[,1] %>% set_names("wl") %>% rowid_to_column()

## DEMON data
L_Demon <- map(c("ss406.asc","ss407.asc","ss408.asc","ss409.asc","ss410.asc"), 
               ~ read_tsv(paste(data.dir,.x,sep = ""), col_names = F, progress = F, show_col_types = F)) 

L_Demon <- L_Demon %>% set_names(c("ss406","ss407","ss408","ss409","ss410"))  

L_Demon <- L_Demon %>% map(~ .x %>% setNames(c("wl",paste("X", 1:(ncol(.x)-1), sep = ""))))

## elimina shot 1
L_Demon <- L_Demon %>% 
  map(~ .x %>% .[, c(1, which(Metadata$z != 1) + 1)]) ## elimina disparo #1 (limpieza)

g <- L_Demon %>% map(~ data.frame(.x[,1], Int = apply(.x[,2:ncol(.x)], 1, mean))) %>% bind_rows(.id = "id") %>% 
  ggplot(aes(x = wl, y = Int, color = id)) + geom_line() + labs(x = "Wavelength")
g %>% plotly::ggplotly()
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
## Normalizar
izq <- 267.70
der <- 267.75
int <- L_Demon %>% map_dfr(fun.int, izq = izq, der = der)
factor <-  1
int_norm <- int/factor

## acumular
int_norm <- sumar_filas_por_grupos(int_norm, n = 10, wl = F)

## Promediar
int_norm <- cbind(Comp.data, int_norm)
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>%
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean <- apply(int_norm %>% select(X1:X100), 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)
int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_boxplot() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

MECHELLE

data.dir <- "Data/mechelle/"
## Mechelle data
L_Mechelle <- map(c("ss406.asc","ss407.asc","ss408.asc","ss409.asc","ss410.asc"), 
                  ~ read_tsv(paste(data.dir,.x,sep = ""), col_names = F, progress = F, show_col_types = F)) 

L_Mechelle <- L_Mechelle %>% map(~ .x %>% setNames(c("wl",paste("X", 1:(ncol(.x)-1), sep = ""))))
L_Mechelle <- L_Mechelle %>% set_names(c("ss406","ss407","ss408","ss409","ss410"))  

Exploracion Manual (Cromo)

El spectrometer tiene un gran problema de calibracion. Los espectros se desplazan en longitud de onda. En el siguiente apartado implemento una funcion para recalibrar el espectro tomando como referencia una linea de la matriz (en este caso Fe 438.32).

Wavelength Re-Calibration

ref <- 438.3275
p <- data.frame(L_Mechelle[[1]][,1], Int = apply(L_Mechelle[[1]][,2:ncol(L_Mechelle[[1]])], 1, mean))
p$wl <- round(p$wl,4)
p <- which(p$wl == 438.3275)

L_Mechelle_new <- L_Mechelle %>% 
    map(~ fun.WL.calibration(old = .x, p = p))

L_Mechelle_new <- L_Mechelle_new %>% 
                    map(~ .x %>% drop_na() %>% filter(between(rowid, 1, 26818)) %>% select(!rowid))

Normalizacion: Estandar interno

¿Como tratar los datos? - ¿Que es una observacion?

  • Metodo 1: Acumular (z) - Normalizar - Promediar (x)
## acumular
L <- L_Mechelle_new %>% map(~ .x %>% sumar_filas_por_grupos(n = 10))
  
## Normalizar
int <- L %>% map_dfr(fun.int, izq = 267.64, der = 267.74)       ## Cromo
factor <- L %>% map_dfr(fun.int, izq = 268.40, der = 268.50)    ## Fe
int_norm <- int/factor

## Promediar
int_norm <- cbind(Comp.data, int_norm)

int_mean <- apply(int_norm %>% select(X1:X100), 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)

## graficar
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>% 
    ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
        geom_point()


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_violin() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

  • Metodo 2: Normalizar - Acumular (z) - promediar (x)
## Normalizar: por espectro
int <- L_Mechelle_new %>% map_dfr(fun.int, izq = 267.64, der = 267.74)
factor <- L_Mechelle_new %>% map_dfr(fun.int, izq = 268.40, der = 268.50)
int_norm <- int/factor

## acumular: en Z
int_norm <- sumar_filas_por_grupos(int_norm, n = 10, wl = F)

## Promediar: en X
int_mean <- apply(int_norm, 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)
int_norm <- cbind(Comp.data, int_norm)

## graficar
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>% 
    ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
        geom_point()


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_violin() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

Nota: En adelante una observacion sera el resultado de aplicar Metodo 1.

Normalizacion: suma total

Acumular (z) - Normalizar - Promediar (x)

## Acumular
L <- L_Mechelle_new %>% map(~ .x %>% sumar_filas_por_grupos(n = 10))
  
## Normalizar
int <- L %>% map_dfr(fun.int, izq = 267.64, der = 267.74)       ## Cromo
factor <- L %>% map_dfr(fun.int, izq = 230, der = 1000)    ## Fe
int_norm <- int/factor

## Promediar
int_norm <- cbind(Comp.data, int_norm)

int_mean <- apply(int_norm %>% select(X1:X100), 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)

## graficar
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>% 
    ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
        geom_point()


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_violin() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

Normalizacion: Porcion del espectro

## acumular
L <- L_Mechelle_new %>% map(~ .x %>% sumar_filas_por_grupos(n = 10))
  
## Normalizar
int <- L %>% map_dfr(fun.int, izq = 267.64, der = 267.74)       ## Cromo
factor <- L %>% map_dfr(fun.int, izq = 230, der = 320)    ## Fe
int_norm <- int/factor

## Promediar
int_norm <- cbind(Comp.data, int_norm)

int_mean <- apply(int_norm %>% select(X1:X100), 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)

## graficar
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>% 
    ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
        geom_point()


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")


int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_violin() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

PLS (+Lasso) - Exploracion

Crear data X,Y

## acumular
L <- L_Mechelle_new %>% map(~ .x %>% sumar_filas_por_grupos(n = 10))
  
## Normalizar
int <- L %>% map_dfr(fun.int, izq = 267.64, der = 267.74)       ## Cromo
factor <- L %>% map_dfr(fun.int, izq = 268.40, der = 268.50)    ## Fe
int_norm <- int/factor

## Promediar
int_norm <- cbind(Comp.data, int_norm)

int_mean <- apply(int_norm %>% select(X1:X100), 1, promediar_grupos_aleatorios, n=10) %>% t() %>% data.frame()
int_mean <- cbind(Comp.data, int_mean)

## graficar
int_norm %>% pivot_longer(X1:X100, values_to = "Libs.Int") %>% 
    ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
        geom_point()

int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_point() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")

int_mean %>% pivot_longer(X1:X10, values_to = "Libs.Int") %>% 
  ggplot(aes(x = Libs.Int, y = Cr, color = muestra)) + 
    geom_violin() + 
    geom_hline(yintercept = int_norm$Cr, lty = 2, col = "gray")
library(mixOmics)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlLCB2ZXJib3NlID0gRikKc291cmNlKCJGdW5jaW9uZXMuUiIpCmBgYAoKIyBMZWN0dXJhIGRlIERhdG9zCgpMbyBkYXRvcyBjb3JyZXNwb25kZSBhIHVuYSBtYXRyaXogNXg1eDEwLiBMYSBtZXRhZGF0YSBzZXLDoSBYID0gMS4uLjI1IHkgWiA9IDEuLi4xMCAocHJvZnVuZGlkYWQpLCBhbWJvcyBkZXRlY3RvcmVzIHRpZW5lbiBsYSBtaXNtYSBtZXRhZGF0YS4KCmBgYHtyfQojI01ldGFkYXRhCk1ldGFkYXRhIDwtIGRhdGEuZnJhbWUoeCA9IHJlcCgxOjEwMCwgZWFjaCA9IDExKSwgCiAgICAgICAgICAgICAgICAgICAgICAgeiA9IHJlcCgxOjExLCAxMDApKQoKQ29tcC5kYXRhIDwtIGRhdGEuZnJhbWUobXVlc3RyYSA9IGMoInNzNDA2IiwgInNzNDA3IiwgInNzNDA4IiwgInNzNDA5IiwgInNzNDEwIiksIAogICAgICAgICAgICAgICAgICAgICAgICBDID0gYygwLjE5LCAwLjUwLCAwLjI4LCAwLjExLCAwLjM5KSwKICAgICAgICAgICAgICAgICAgICAgICAgU2kgPSBjKDAuMzgsIDAuNjksIDAuMjQsIDEuMDcsIDEuMDApLAogICAgICAgICAgICAgICAgICAgICAgICBTID0gYygwLjA0OSwgMC4wMTIsIDAuMDMwLCAwLjAxNSwgMC4wNTMpLAogICAgICAgICAgICAgICAgICAgICAgICBQID0gYygwLjAxNCwgMC4wMzMsIDAuMDQzLCAwLjAyNSwgMC4wNjYpLAogICAgICAgICAgICAgICAgICAgICAgICBNbiA9IGMoMC41MywgMC4xMywgMC42NCwgMC40OCwgMC40MyksCiAgICAgICAgICAgICAgICAgICAgICAgIE5pID0gYygxLjY5LCAwLjYxLCA0LjU4LCAzLjE0LCAyLjA0KSwKICAgICAgICAgICAgICAgICAgICAgICAgQ3IgPSBjKDIuMTIsIDMuMDAsIDAuMDksIDEuMjIsIDEuNzIpLAogICAgICAgICAgICAgICAgICAgICAgICBNbyA9IGMoMS4wMywgMC44MiwgMC4xNCwgMC43NywgMC40MSksCiAgICAgICAgICAgICAgICAgICAgICAgIFYgPSBjKDAuMDIwLCAwLjIzLCAwLjA2MywgMC4wMjgsIDAuNDYpLAogICAgICAgICAgICAgICAgICAgICAgICBDdSA9IGMoMC4zMiwgMC40MywgMC43MywgMC4yMywgMC40NykpCmBgYAoKIyBERU1PTgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmRhdGEuZGlyIDwtICJEYXRhL2RlbW9uLyIKCndsIDwtIHJlYWRfdHN2KHBhc3RlKGRhdGEuZGlyLCJzczQwNi5hc2MiLHNlcCA9ICIiKSwgY29sX25hbWVzID0gRiwgcHJvZ3Jlc3MgPSBGLCBzaG93X2NvbF90eXBlcyA9IEYpICU+JSAKICAgICAgICAuWywxXSAlPiUgc2V0X25hbWVzKCJ3bCIpICU+JSByb3dpZF90b19jb2x1bW4oKQoKIyMgREVNT04gZGF0YQpMX0RlbW9uIDwtIG1hcChjKCJzczQwNi5hc2MiLCJzczQwNy5hc2MiLCJzczQwOC5hc2MiLCJzczQwOS5hc2MiLCJzczQxMC5hc2MiKSwgCiAgICAgICAgICAgICAgIH4gcmVhZF90c3YocGFzdGUoZGF0YS5kaXIsLngsc2VwID0gIiIpLCBjb2xfbmFtZXMgPSBGLCBwcm9ncmVzcyA9IEYsIHNob3dfY29sX3R5cGVzID0gRikpIAoKTF9EZW1vbiA8LSBMX0RlbW9uICU+JSBzZXRfbmFtZXMoYygic3M0MDYiLCJzczQwNyIsInNzNDA4Iiwic3M0MDkiLCJzczQxMCIpKSAgCgpMX0RlbW9uIDwtIExfRGVtb24gJT4lIG1hcCh+IC54ICU+JSBzZXROYW1lcyhjKCJ3bCIscGFzdGUoIlgiLCAxOihuY29sKC54KS0xKSwgc2VwID0gIiIpKSkpCgojIyBlbGltaW5hIHNob3QgMQpMX0RlbW9uIDwtIExfRGVtb24gJT4lIAogIG1hcCh+IC54ICU+JSAuWywgYygxLCB3aGljaChNZXRhZGF0YSR6ICE9IDEpICsgMSldKSAjIyBlbGltaW5hIGRpc3Bhcm8gIzEgKGxpbXBpZXphKQoKZyA8LSBMX0RlbW9uICU+JSBtYXAofiBkYXRhLmZyYW1lKC54WywxXSwgSW50ID0gYXBwbHkoLnhbLDI6bmNvbCgueCldLCAxLCBtZWFuKSkpICU+JSBiaW5kX3Jvd3MoLmlkID0gImlkIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHdsLCB5ID0gSW50LCBjb2xvciA9IGlkKSkgKyBnZW9tX2xpbmUoKSArIGxhYnMoeCA9ICJXYXZlbGVuZ3RoIikKZyAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpCmBgYAoKYGBge3J9CiMjIE5vcm1hbGl6YXIKaXpxIDwtIDI2Ny43MApkZXIgPC0gMjY3Ljc1CmludCA8LSBMX0RlbW9uICU+JSBtYXBfZGZyKGZ1bi5pbnQsIGl6cSA9IGl6cSwgZGVyID0gZGVyKQpmYWN0b3IgPC0gIDEKaW50X25vcm0gPC0gaW50L2ZhY3RvcgoKIyMgYWN1bXVsYXIKaW50X25vcm0gPC0gc3VtYXJfZmlsYXNfcG9yX2dydXBvcyhpbnRfbm9ybSwgbiA9IDEwLCB3bCA9IEYpCgojIyBQcm9tZWRpYXIKaW50X25vcm0gPC0gY2JpbmQoQ29tcC5kYXRhLCBpbnRfbm9ybSkKaW50X25vcm0gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBpbnRfbm9ybSRDciwgbHR5ID0gMiwgY29sID0gImdyYXkiKQoKaW50X21lYW4gPC0gYXBwbHkoaW50X25vcm0gJT4lIHNlbGVjdChYMTpYMTAwKSwgMSwgcHJvbWVkaWFyX2dydXBvc19hbGVhdG9yaW9zLCBuPTEwKSAlPiUgdCgpICU+JSBkYXRhLmZyYW1lKCkKaW50X21lYW4gPC0gY2JpbmQoQ29tcC5kYXRhLCBpbnRfbWVhbikKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBpbnRfbm9ybSRDciwgbHR5ID0gMiwgY29sID0gImdyYXkiKQoKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGludF9ub3JtJENyLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpCgpgYGAKCiMgTUVDSEVMTEUKCmBgYHtyfQpkYXRhLmRpciA8LSAiRGF0YS9tZWNoZWxsZS8iCiMjIE1lY2hlbGxlIGRhdGEKTF9NZWNoZWxsZSA8LSBtYXAoYygic3M0MDYuYXNjIiwic3M0MDcuYXNjIiwic3M0MDguYXNjIiwic3M0MDkuYXNjIiwic3M0MTAuYXNjIiksIAogICAgICAgICAgICAgICAgICB+IHJlYWRfdHN2KHBhc3RlKGRhdGEuZGlyLC54LHNlcCA9ICIiKSwgY29sX25hbWVzID0gRiwgcHJvZ3Jlc3MgPSBGLCBzaG93X2NvbF90eXBlcyA9IEYpKSAKCkxfTWVjaGVsbGUgPC0gTF9NZWNoZWxsZSAlPiUgbWFwKH4gLnggJT4lIHNldE5hbWVzKGMoIndsIixwYXN0ZSgiWCIsIDE6KG5jb2woLngpLTEpLCBzZXAgPSAiIikpKSkKTF9NZWNoZWxsZSA8LSBMX01lY2hlbGxlICU+JSBzZXRfbmFtZXMoYygic3M0MDYiLCJzczQwNyIsInNzNDA4Iiwic3M0MDkiLCJzczQxMCIpKSAgCmBgYAoKIyMgRXhwbG9yYWNpb24gTWFudWFsIChDcm9tbykKCmBgYHtyfQojIyBlbGltaW5hIHNob3QgMQpMX01lY2hlbGxlIDwtIExfTWVjaGVsbGUgJT4lIAogIG1hcCh+IC54ICU+JSAuWywgYygxLCB3aGljaChNZXRhZGF0YSR6ICE9IDEpICsgMSldKSAjIyBlbGltaW5hIGRpc3Bhcm8gIzEgKGxpbXBpZXphKQoKZyA8LSBMX01lY2hlbGxlICU+JSBtYXAofiBkYXRhLmZyYW1lKC54WywxXSwgSW50ID0gYXBwbHkoLnhbLDI6bmNvbCgueCldLCAxLCBtZWFuKSkpICU+JSBiaW5kX3Jvd3MoLmlkID0gImlkIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHdsLCB5ID0gSW50LCBjb2xvciA9IGlkKSkgKyBnZW9tX2xpbmUoKSArIGxhYnMoeCA9ICJXYXZlbGVuZ3RoIikKZyAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpCmBgYAoKRWwgc3BlY3Ryb21ldGVyIHRpZW5lIHVuIGdyYW4gcHJvYmxlbWEgZGUgY2FsaWJyYWNpb24uIExvcyBlc3BlY3Ryb3Mgc2UgZGVzcGxhemFuIGVuIGxvbmdpdHVkIGRlIG9uZGEuIEVuIGVsIHNpZ3VpZW50ZSBhcGFydGFkbyBpbXBsZW1lbnRvIHVuYSBmdW5jaW9uIHBhcmEgcmVjYWxpYnJhciBlbCBlc3BlY3RybyB0b21hbmRvIGNvbW8gcmVmZXJlbmNpYSB1bmEgbGluZWEgZGUgbGEgbWF0cml6IChlbiBlc3RlIGNhc28gRmUgNDM4LjMyKS4KCiMjIyBXYXZlbGVuZ3RoIFJlLUNhbGlicmF0aW9uCgpgYGB7cn0KcmVmIDwtIDQzOC4zMjc1CnAgPC0gZGF0YS5mcmFtZShMX01lY2hlbGxlW1sxXV1bLDFdLCBJbnQgPSBhcHBseShMX01lY2hlbGxlW1sxXV1bLDI6bmNvbChMX01lY2hlbGxlW1sxXV0pXSwgMSwgbWVhbikpCnAkd2wgPC0gcm91bmQocCR3bCw0KQpwIDwtIHdoaWNoKHAkd2wgPT0gNDM4LjMyNzUpCgpMX01lY2hlbGxlX25ldyA8LSBMX01lY2hlbGxlICU+JSAKICAgIG1hcCh+IGZ1bi5XTC5jYWxpYnJhdGlvbihvbGQgPSAueCwgcCA9IHApKQoKTF9NZWNoZWxsZV9uZXcgPC0gTF9NZWNoZWxsZV9uZXcgJT4lIAogICAgICAgICAgICAgICAgICAgIG1hcCh+IC54ICU+JSBkcm9wX25hKCkgJT4lIGZpbHRlcihiZXR3ZWVuKHJvd2lkLCAxLCAyNjgxOCkpICU+JSBzZWxlY3QoIXJvd2lkKSkKYGBgCgpgYGB7cn0KZyA8LSBMX01lY2hlbGxlX25ldyAlPiUgcHVycnI6Om1hcCh+IGRhdGEuZnJhbWUod2wgPSAueFssMV0sIEludCA9IGFwcGx5KC54WywyOm5jb2woLngpXSwgMSwgbWVhbikpKSAlPiUgCiAgICAgICAgICAgIGJpbmRfcm93cyguaWQgPSAiaWQiKSAlPiUgCiAgICAgICBnZ3Bsb3QoYWVzKHggPSB3bCwgeSA9IEludCwgY29sb3IgPSBpZCkpICsgZ2VvbV9saW5lKCkgKyBsYWJzKHggPSAiV2F2ZWxlbmd0aCIpCiAKZyAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpCmBgYAoKIyMjIE5vcm1hbGl6YWNpb246IEVzdGFuZGFyIGludGVybm8KCiMjIyMgwr9Db21vIHRyYXRhciBsb3MgZGF0b3M/IC0gwr9RdWUgZXMgdW5hIG9ic2VydmFjaW9uPwoKLSAgICoqTWV0b2RvIDE6IEFjdW11bGFyICh6KSAtIE5vcm1hbGl6YXIgLSBQcm9tZWRpYXIgKHgpKioKCmBgYHtyfQojIyBhY3VtdWxhcgpMIDwtIExfTWVjaGVsbGVfbmV3ICU+JSBtYXAofiAueCAlPiUgc3VtYXJfZmlsYXNfcG9yX2dydXBvcyhuID0gMTApKQogIAojIyBOb3JtYWxpemFyCmludCA8LSBMICU+JSBtYXBfZGZyKGZ1bi5pbnQsIGl6cSA9IDI2Ny42NCwgZGVyID0gMjY3Ljc0KSAgICAgICAjIyBDcm9tbwpmYWN0b3IgPC0gTCAlPiUgbWFwX2RmcihmdW4uaW50LCBpenEgPSAyNjguNDAsIGRlciA9IDI2OC41MCkgICAgIyMgRmUKaW50X25vcm0gPC0gaW50L2ZhY3RvcgoKIyMgUHJvbWVkaWFyCmludF9ub3JtIDwtIGNiaW5kKENvbXAuZGF0YSwgaW50X25vcm0pCgppbnRfbWVhbiA8LSBhcHBseShpbnRfbm9ybSAlPiUgc2VsZWN0KFgxOlgxMDApLCAxLCBwcm9tZWRpYXJfZ3J1cG9zX2FsZWF0b3Jpb3MsIG49MTApICU+JSB0KCkgJT4lIGRhdGEuZnJhbWUoKQppbnRfbWVhbiA8LSBjYmluZChDb21wLmRhdGEsIGludF9tZWFuKQoKIyMgZ3JhZmljYXIKaW50X25vcm0gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgICAgIGdlb21fcG9pbnQoKQoKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBpbnRfbm9ybSRDciwgbHR5ID0gMiwgY29sID0gImdyYXkiKQoKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV92aW9saW4oKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaW50X25vcm0kQ3IsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikKYGBgCgotICAgKipNZXRvZG8gMjogTm9ybWFsaXphciAtIEFjdW11bGFyICh6KSAtIHByb21lZGlhciAoeCkqKgoKYGBge3J9CiMjIE5vcm1hbGl6YXI6IHBvciBlc3BlY3RybwppbnQgPC0gTF9NZWNoZWxsZV9uZXcgJT4lIG1hcF9kZnIoZnVuLmludCwgaXpxID0gMjY3LjY0LCBkZXIgPSAyNjcuNzQpCmZhY3RvciA8LSBMX01lY2hlbGxlX25ldyAlPiUgbWFwX2RmcihmdW4uaW50LCBpenEgPSAyNjguNDAsIGRlciA9IDI2OC41MCkKaW50X25vcm0gPC0gaW50L2ZhY3RvcgoKIyMgYWN1bXVsYXI6IGVuIFoKaW50X25vcm0gPC0gc3VtYXJfZmlsYXNfcG9yX2dydXBvcyhpbnRfbm9ybSwgbiA9IDEwLCB3bCA9IEYpCgojIyBQcm9tZWRpYXI6IGVuIFgKaW50X21lYW4gPC0gYXBwbHkoaW50X25vcm0sIDEsIHByb21lZGlhcl9ncnVwb3NfYWxlYXRvcmlvcywgbj0xMCkgJT4lIHQoKSAlPiUgZGF0YS5mcmFtZSgpCmludF9tZWFuIDwtIGNiaW5kKENvbXAuZGF0YSwgaW50X21lYW4pCmludF9ub3JtIDwtIGNiaW5kKENvbXAuZGF0YSwgaW50X25vcm0pCgojIyBncmFmaWNhcgppbnRfbm9ybSAlPiUgcGl2b3RfbG9uZ2VyKFgxOlgxMDAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IExpYnMuSW50LCB5ID0gQ3IsIGNvbG9yID0gbXVlc3RyYSkpICsgCiAgICAgICAgZ2VvbV9wb2ludCgpCgppbnRfbWVhbiAlPiUgcGl2b3RfbG9uZ2VyKFgxOlgxMCwgdmFsdWVzX3RvID0gIkxpYnMuSW50IikgJT4lIAogIGdncGxvdChhZXMoeCA9IExpYnMuSW50LCB5ID0gQ3IsIGNvbG9yID0gbXVlc3RyYSkpICsgCiAgICBnZW9tX3BvaW50KCkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGludF9ub3JtJENyLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpCgppbnRfbWVhbiAlPiUgcGl2b3RfbG9uZ2VyKFgxOlgxMCwgdmFsdWVzX3RvID0gIkxpYnMuSW50IikgJT4lIAogIGdncGxvdChhZXMoeCA9IExpYnMuSW50LCB5ID0gQ3IsIGNvbG9yID0gbXVlc3RyYSkpICsgCiAgICBnZW9tX3Zpb2xpbigpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBpbnRfbm9ybSRDciwgbHR5ID0gMiwgY29sID0gImdyYXkiKQpgYGAKCipOb3RhOiogRW4gYWRlbGFudGUgdW5hIG9ic2VydmFjaW9uIHNlcmEgZWwgcmVzdWx0YWRvIGRlIGFwbGljYXIgTWV0b2RvIDEuCgojIyMgTm9ybWFsaXphY2lvbjogc3VtYSB0b3RhbAoKQWN1bXVsYXIgKHopIC0gTm9ybWFsaXphciAtIFByb21lZGlhciAoeCkKCmBgYHtyfQojIyBBY3VtdWxhcgpMIDwtIExfTWVjaGVsbGVfbmV3ICU+JSBtYXAofiAueCAlPiUgc3VtYXJfZmlsYXNfcG9yX2dydXBvcyhuID0gMTApKQogIAojIyBOb3JtYWxpemFyCmludCA8LSBMICU+JSBtYXBfZGZyKGZ1bi5pbnQsIGl6cSA9IDI2Ny42NCwgZGVyID0gMjY3Ljc0KSAgICAgICAjIyBDcm9tbwpmYWN0b3IgPC0gTCAlPiUgbWFwX2RmcihmdW4uaW50LCBpenEgPSAyMzAsIGRlciA9IDEwMDApICAgICMjIEZlCmludF9ub3JtIDwtIGludC9mYWN0b3IKCiMjIFByb21lZGlhcgppbnRfbm9ybSA8LSBjYmluZChDb21wLmRhdGEsIGludF9ub3JtKQoKaW50X21lYW4gPC0gYXBwbHkoaW50X25vcm0gJT4lIHNlbGVjdChYMTpYMTAwKSwgMSwgcHJvbWVkaWFyX2dydXBvc19hbGVhdG9yaW9zLCBuPTEwKSAlPiUgdCgpICU+JSBkYXRhLmZyYW1lKCkKaW50X21lYW4gPC0gY2JpbmQoQ29tcC5kYXRhLCBpbnRfbWVhbikKCiMjIGdyYWZpY2FyCmludF9ub3JtICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwMCwgdmFsdWVzX3RvID0gIkxpYnMuSW50IikgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgICAgICBnZW9tX3BvaW50KCkKCmludF9tZWFuICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgIGdlb21fcG9pbnQoKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaW50X25vcm0kQ3IsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikKCmludF9tZWFuICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgIGdlb21fdmlvbGluKCkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGludF9ub3JtJENyLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpCmBgYAoKIyMjIE5vcm1hbGl6YWNpb246IFBvcmNpb24gZGVsIGVzcGVjdHJvCgpgYGB7cn0KIyMgYWN1bXVsYXIKTCA8LSBMX01lY2hlbGxlX25ldyAlPiUgbWFwKH4gLnggJT4lIHN1bWFyX2ZpbGFzX3Bvcl9ncnVwb3MobiA9IDEwKSkKICAKIyMgTm9ybWFsaXphcgppbnQgPC0gTCAlPiUgbWFwX2RmcihmdW4uaW50LCBpenEgPSAyNjcuNjQsIGRlciA9IDI2Ny43NCkgICAgICAgIyMgQ3JvbW8KZmFjdG9yIDwtIEwgJT4lIG1hcF9kZnIoZnVuLmludCwgaXpxID0gMjMwLCBkZXIgPSAzMjApICAgICMjIEZlCmludF9ub3JtIDwtIGludC9mYWN0b3IKCiMjIFByb21lZGlhcgppbnRfbm9ybSA8LSBjYmluZChDb21wLmRhdGEsIGludF9ub3JtKQoKaW50X21lYW4gPC0gYXBwbHkoaW50X25vcm0gJT4lIHNlbGVjdChYMTpYMTAwKSwgMSwgcHJvbWVkaWFyX2dydXBvc19hbGVhdG9yaW9zLCBuPTEwKSAlPiUgdCgpICU+JSBkYXRhLmZyYW1lKCkKaW50X21lYW4gPC0gY2JpbmQoQ29tcC5kYXRhLCBpbnRfbWVhbikKCiMjIGdyYWZpY2FyCmludF9ub3JtICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwMCwgdmFsdWVzX3RvID0gIkxpYnMuSW50IikgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgICAgICBnZW9tX3BvaW50KCkKCmludF9tZWFuICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgIGdlb21fcG9pbnQoKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaW50X25vcm0kQ3IsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikKCmludF9tZWFuICU+JSBwaXZvdF9sb25nZXIoWDE6WDEwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTGlicy5JbnQsIHkgPSBDciwgY29sb3IgPSBtdWVzdHJhKSkgKyAKICAgIGdlb21fdmlvbGluKCkgKyAKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGludF9ub3JtJENyLCBsdHkgPSAyLCBjb2wgPSAiZ3JheSIpCmBgYAoKIyBQTFMgKCtMYXNzbykgLSBFeHBsb3JhY2lvbgoKIyMgQ3JlYXIgZGF0YSBYLFkKCmBgYHtyfQojIyBhY3VtdWxhcgpMIDwtIExfTWVjaGVsbGVfbmV3ICU+JSBtYXAofiAueCAlPiUgc3VtYXJfZmlsYXNfcG9yX2dydXBvcyhuID0gMTApKQogIAojIyBOb3JtYWxpemFyCmludCA8LSBMICU+JSBtYXBfZGZyKGZ1bi5pbnQsIGl6cSA9IDI2Ny42NCwgZGVyID0gMjY3Ljc0KSAgICAgICAjIyBDcm9tbwpmYWN0b3IgPC0gTCAlPiUgbWFwX2RmcihmdW4uaW50LCBpenEgPSAyNjguNDAsIGRlciA9IDI2OC41MCkgICAgIyMgRmUKaW50X25vcm0gPC0gaW50L2ZhY3RvcgoKIyMgUHJvbWVkaWFyCmludF9ub3JtIDwtIGNiaW5kKENvbXAuZGF0YSwgaW50X25vcm0pCgppbnRfbWVhbiA8LSBhcHBseShpbnRfbm9ybSAlPiUgc2VsZWN0KFgxOlgxMDApLCAxLCBwcm9tZWRpYXJfZ3J1cG9zX2FsZWF0b3Jpb3MsIG49MTApICU+JSB0KCkgJT4lIGRhdGEuZnJhbWUoKQppbnRfbWVhbiA8LSBjYmluZChDb21wLmRhdGEsIGludF9tZWFuKQoKIyMgZ3JhZmljYXIKaW50X25vcm0gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAwLCB2YWx1ZXNfdG8gPSAiTGlicy5JbnQiKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgICAgIGdlb21fcG9pbnQoKQoKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV9wb2ludCgpICsgCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBpbnRfbm9ybSRDciwgbHR5ID0gMiwgY29sID0gImdyYXkiKQoKaW50X21lYW4gJT4lIHBpdm90X2xvbmdlcihYMTpYMTAsIHZhbHVlc190byA9ICJMaWJzLkludCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBMaWJzLkludCwgeSA9IENyLCBjb2xvciA9IG11ZXN0cmEpKSArIAogICAgZ2VvbV92aW9saW4oKSArIAogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gaW50X25vcm0kQ3IsIGx0eSA9IDIsIGNvbCA9ICJncmF5IikKYGBgCgpgYGB7cn0KbGlicmFyeShtaXhPbWljcykKCmBgYAo=